import socket
# 导入 socket 模块，用于创建网络套接字，实现网络通信

# 创建 TCP 套接字
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 创建一个 TCP 套接字对象
# socket.AF_INET 表示使用 IPv4 地址族
# socket.SOCK_STREAM 表示使用面向连接的 TCP 协议

# 绑定地址和端口
server_socket.bind(('localhost', 70))
# 将套接字绑定到本地地址（localhost）和 Gopher 协议默认端口 70

# 开始监听，最大连接数为 1
server_socket.listen(1)
# 让套接字开始监听客户端的连接请求
# 最大连接数设置为 1，表示同一时间最多处理 1 个客户端连接

print("Gopher server is listening on port 70...")
# 打印提示信息，表明服务器已经启动并开始监听 70 端口

while True:
    # 进入一个无限循环，持续等待客户端的连接
    # 接受客户端连接
    client_socket, client_address = server_socket.accept()
    # 阻塞等待客户端连接
    # 若有客户端连接，返回一个新的套接字对象 client_socket 用于与客户端通信
    # 同时返回客户端的地址信息 client_address

    print(f"Accepted connection from {client_address}")
    # 打印接受的客户端连接信息

    # ==================== 原方案 ====================
    # 接收客户端请求
    request = client_socket.recv(1024).decode('utf-8').strip()
    # 从客户端套接字接收最多 1024 字节的数据
    # 使用 decode('utf-8') 方法将字节数据解码为字符串
    # 使用 strip() 方法去除字符串两端的空白字符

    print(f"Received request: {request}")
    # 打印接收到的客户端请求信息

    # 模拟返回数据
    response = "This is a test response from Gopher server.\r\n"
    # 定义要返回给客户端的响应数据

    client_socket.sendall(response.encode('utf-8'))
    # 使用 encode('utf-8') 方法将响应数据编码为字节类型
    # 调用 sendall 方法将字节数据完整地发送给客户端

    # 关闭客户端连接
    client_socket.close()
    # 关闭与客户端通信的套接字，释放系统资源

    # ==================== 新方案（使用 makefile） ====================
    # 以下是使用 makefile 函数的新方案，它能让网络套接字的读写操作更像操作文件
    # 并且自动处理编码解码，代码更简洁易读

    # # 如果要测试新方案，需取消注释以下代码并注释掉上面原方案的代码
    # # 使用 makefile 创建读写文件对象
    # client_file = client_socket.makefile('rw', encoding='utf-8')

    # try:
    #     # 接收客户端请求
    #     request = client_file.readline().strip()
    #     print(f"Received request: {request}")

    #     # 模拟返回数据
    #     response = "This is a test response from Gopher server.\r\n"
    #     client_file.write(response)
    #     client_file.flush()  # 确保数据发送
    # except Exception as e:
    #     print(f"Error handling client: {e}")
    # finally:
    #     # 关闭文件对象和客户端套接字
    #     client_file.close()
    #     client_socket.close()